package com.example.a_java.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.a_java.dto.BatchReminderDTO;
import com.example.a_java.dto.CollectionRecordDTO;
import com.example.a_java.dto.OverdueRepayDTO;
import com.example.a_java.dto.RepaymentRecordDTO;
import com.example.a_java.dto.RepaymentReminderDTO;
import com.example.a_java.entity.LoanCollectionRecord;
import com.example.a_java.entity.LoanContract;
import com.example.a_java.entity.LoanOverdue;
import com.example.a_java.entity.LoanRepaymentPlan;
import com.example.a_java.entity.LoanRepaymentRecord;
import com.example.a_java.entity.LoanRepaymentReminder;
import com.example.a_java.mapper.LoanCollectionRecordMapper;
import com.example.a_java.mapper.LoanContractMapper;
import com.example.a_java.mapper.LoanOverdueMapper;
import com.example.a_java.mapper.LoanRepaymentPlanMapper;
import com.example.a_java.mapper.LoanRepaymentRecordMapper;
import com.example.a_java.mapper.LoanRepaymentReminderMapper;
import com.example.a_java.service.OverdueService;
import com.example.a_java.service.RepaymentRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 逾期管理Service实现�?
 */
@Service
@Slf4j
public class OverdueServiceImpl extends ServiceImpl<LoanOverdueMapper, LoanOverdue> implements OverdueService {

    @Autowired
    private LoanOverdueMapper overdueMapper;
    
    @Autowired
    private LoanRepaymentReminderMapper reminderMapper;
    
    @Autowired
    private LoanCollectionRecordMapper collectionRecordMapper;
    
    @Autowired
    private LoanRepaymentPlanMapper repaymentPlanMapper;
    
    @Autowired
    private LoanRepaymentRecordMapper repaymentRecordMapper;
    
    @Autowired
    private LoanContractMapper contractMapper;
    
    @Autowired
    private RepaymentRecordService repaymentRecordService;

    @Override
    public IPage<LoanOverdue> getOverdueList(Page<LoanOverdue> page, String loanNo, String customerName, String overdueDays, String status) {
        LambdaQueryWrapper<LoanOverdue> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LoanOverdue::getIsDeleted, 0);
        
        if (StringUtils.isNotBlank(loanNo)) {
            wrapper.like(LoanOverdue::getLoanNo, loanNo);
        }
        
        if (StringUtils.isNotBlank(customerName)) {
            wrapper.like(LoanOverdue::getCustomerName, customerName);
        }
        
        if (StringUtils.isNotBlank(overdueDays)) {
            try {
                String[] days = overdueDays.split("-");
                if (days.length == 2) {
                    int minDays = Integer.parseInt(days[0]);
                    int maxDays = Integer.parseInt(days[1]);
                    wrapper.ge(LoanOverdue::getOverdueDays, minDays);
                    wrapper.le(LoanOverdue::getOverdueDays, maxDays);
                } else {
                    int days1 = Integer.parseInt(overdueDays);
                    wrapper.eq(LoanOverdue::getOverdueDays, days1);
                }
            } catch (Exception e) {
                log.error("解析逾期天数异常", e);
            }
        }
        
        if (StringUtils.isNotBlank(status)) {
            wrapper.eq(LoanOverdue::getStatus, status);
        }
        
        wrapper.orderByDesc(LoanOverdue::getOverdueDays);
        
        return overdueMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> sendRepaymentReminder(RepaymentReminderDTO reminderDTO) {
        Map<String, Object> result = new HashMap<>();
        
        // 1. 查询逾期记录
        LoanOverdue overdue = overdueMapper.selectById(reminderDTO.getOverdueId());
        if (overdue == null) {
            throw new RuntimeException("逾期记录不存在");
        }
        
        // 2. 创建提醒记录
        LoanRepaymentReminder reminder = new LoanRepaymentReminder();
        reminder.setOverdueId(reminderDTO.getOverdueId());
        reminder.setMethod(reminderDTO.getMethod());
        reminder.setContent(reminderDTO.getContent());
        reminder.setPhone(reminderDTO.getPhone());
        reminder.setEmail(reminderDTO.getEmail());
        reminder.setRemindTime(LocalDateTime.now());
        reminder.setSendStatus(1); // 成功
        reminder.setCreateTime(LocalDateTime.now());
        reminder.setIsDeleted(0);
        
        // 3. 保存提醒记录
        reminderMapper.insert(reminder);
        
        // 4. 更新逾期记录状�?
        overdue.setStatus("reminded");
        overdue.setLastRemindTime(LocalDateTime.now());
        overdue.setRemindCount(overdue.getRemindCount() == null ? 1 : overdue.getRemindCount() + 1);
        overdue.setUpdateTime(LocalDateTime.now());
        overdueMapper.updateById(overdue);
        
        // 5. 返回结果
        result.put("remindId", reminder.getRemindId());
        result.put("remindTime", reminder.getRemindTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> batchSendReminder(BatchReminderDTO batchReminderDTO) {
        Map<String, Object> result = new HashMap<>();
        int successCount = 0;
        int failCount = 0;
        List<String> failReasons = new ArrayList<>();
        
        for (Long overdueId : batchReminderDTO.getOverdueIds()) {
            try {
                // 1. 查询逾期记录
                LoanOverdue overdue = overdueMapper.selectById(overdueId);
                if (overdue == null) {
                    failCount++;
                    failReasons.add("逾期记录ID " + overdueId + " 不存在");
                    continue;
                }
                
                // 2. 创建提醒记录
                LoanRepaymentReminder reminder = new LoanRepaymentReminder();
                reminder.setOverdueId(overdueId);
                reminder.setMethod(batchReminderDTO.getMethod());
                reminder.setContent(batchReminderDTO.getContent());
                reminder.setPhone(overdue.getPhone());
                reminder.setRemindTime(LocalDateTime.now());
                reminder.setSendStatus(1); // 成功
                reminder.setCreateTime(LocalDateTime.now());
                reminder.setIsDeleted(0);
                
                // 3. 保存提醒记录
                reminderMapper.insert(reminder);
                
                // 4. 更新逾期记录状�?
                overdue.setStatus("reminded");
                overdue.setLastRemindTime(LocalDateTime.now());
                overdue.setRemindCount(overdue.getRemindCount() == null ? 1 : overdue.getRemindCount() + 1);
                overdue.setUpdateTime(LocalDateTime.now());
                overdueMapper.updateById(overdue);
                
                successCount++;
            } catch (Exception e) {
                log.error("批量发送提醒异常，逾期ID: " + overdueId, e);
                failCount++;
                failReasons.add("逾期记录ID " + overdueId + " 处理异常: " + e.getMessage());
            }
        }
        
        // 5. 返回结果
        result.put("successCount", successCount);
        result.put("failCount", failCount);
        result.put("failReasons", failReasons);
        result.put("remindTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> collectRecord(CollectionRecordDTO collectionDTO) {
        Map<String, Object> result = new HashMap<>();
        
        // 1. 查询逾期记录
        LoanOverdue overdue = overdueMapper.selectById(collectionDTO.getOverdueId());
        if (overdue == null) {
            throw new RuntimeException("逾期记录不存在");
        }
        
        // 2. 创建催收记录
        LoanCollectionRecord record = new LoanCollectionRecord();
        record.setOverdueId(collectionDTO.getOverdueId());
        record.setMethod(collectionDTO.getMethod());
        record.setCollector(collectionDTO.getCollector());
        record.setCollectTime(LocalDateTime.parse(collectionDTO.getCollectTime(), 
                             DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        record.setResult(collectionDTO.getResult());
        
        if (StringUtils.isNotBlank(collectionDTO.getNextCollectTime())) {
            record.setNextCollectTime(LocalDateTime.parse(collectionDTO.getNextCollectTime(), 
                                     DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        
        record.setRemark(collectionDTO.getRemark());
        record.setCreateTime(LocalDateTime.now());
        record.setIsDeleted(0);
        
        // 3. 保存催收记录
        collectionRecordMapper.insert(record);
        
        // 4. 更新逾期记录状�?
        overdue.setStatus("collected");
        overdue.setUpdateTime(LocalDateTime.now());
        overdueMapper.updateById(overdue);
        
        // 5. 返回结果
        result.put("collectId", record.getCollectId());
        
        return result;
    }

    @Override
    public List<LoanCollectionRecord> getCollectionRecords(Long overdueId) {
        LambdaQueryWrapper<LoanCollectionRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LoanCollectionRecord::getOverdueId, overdueId);
        wrapper.eq(LoanCollectionRecord::getIsDeleted, 0);
        wrapper.orderByDesc(LoanCollectionRecord::getCreateTime);
        
        return collectionRecordMapper.selectList(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> overdueRepay(OverdueRepayDTO overdueRepayDTO) {
        // 1. 查询逾期记录
        LoanOverdue overdue = overdueMapper.selectById(overdueRepayDTO.getOverdueId());
        if (overdue == null) {
            throw new RuntimeException("逾期记录不存在");
        }
        
        // 2. 构建还款记录DTO
        RepaymentRecordDTO recordDTO = new RepaymentRecordDTO();
        recordDTO.setContractId(overdue.getContractId());
        recordDTO.setPlanId(overdue.getPlanId());
        recordDTO.setPayDate(overdueRepayDTO.getPayDate());
        recordDTO.setPayAmount(overdueRepayDTO.getPayAmount());
        recordDTO.setPrincipal(overdueRepayDTO.getPrincipal());
        recordDTO.setInterest(overdueRepayDTO.getInterest());
        recordDTO.setPenalty(overdueRepayDTO.getPenalty());
        recordDTO.setPayMethod(overdueRepayDTO.getPayMethod());
        recordDTO.setTransactionNo(overdueRepayDTO.getTransactionNo());
        recordDTO.setRemark(overdueRepayDTO.getRemark());
        
        // 3. 调用还款记录服务
        Map<String, Object> result = repaymentRecordService.recordRepayment(recordDTO);
        
        // 4. 更新逾期记录状�?
        overdue.setStatus("settled");
        overdue.setUpdateTime(LocalDateTime.now());
        overdueMapper.updateById(overdue);
        
        return result;
    }

    @Override
    public Map<String, Object> getOverdueStatistics(LocalDate startDate, LocalDate endDate) {
        Map<String, Object> result = new HashMap<>();
        
        // 获取各个状态的逾期数量
        QueryWrapper<LoanOverdue> wrapper = new QueryWrapper<>();
        wrapper.select("status, count(*) as count, sum(total_amount) as amount");
        wrapper.eq("is_deleted", 0);
        
        if (startDate != null) {
            wrapper.ge("create_time", startDate.atStartOfDay());
        }
        
        if (endDate != null) {
            wrapper.le("create_time", endDate.plusDays(1).atStartOfDay());
        }
        
        wrapper.groupBy("status");
        
        List<Map<String, Object>> statusStats = overdueMapper.selectMaps(wrapper);
        
        // 获取各个逾期天数段的统计
        QueryWrapper<LoanOverdue> daysWrapper = new QueryWrapper<>();
        daysWrapper.select("count(*) as count, " +
                "sum(CASE WHEN overdue_days <= 30 THEN 1 ELSE 0 END) as days_30, " +
                "sum(CASE WHEN overdue_days > 30 AND overdue_days <= 60 THEN 1 ELSE 0 END) as days_60, " +
                "sum(CASE WHEN overdue_days > 60 AND overdue_days <= 90 THEN 1 ELSE 0 END) as days_90, " +
                "sum(CASE WHEN overdue_days > 90 THEN 1 ELSE 0 END) as days_over_90, " +
                "sum(total_amount) as total_amount, " +
                "sum(CASE WHEN overdue_days <= 30 THEN total_amount ELSE 0 END) as amount_30, " +
                "sum(CASE WHEN overdue_days > 30 AND overdue_days <= 60 THEN total_amount ELSE 0 END) as amount_60, " +
                "sum(CASE WHEN overdue_days > 60 AND overdue_days <= 90 THEN total_amount ELSE 0 END) as amount_90, " +
                "sum(CASE WHEN overdue_days > 90 THEN total_amount ELSE 0 END) as amount_over_90");
        daysWrapper.eq("is_deleted", 0);
        
        if (startDate != null) {
            daysWrapper.ge("create_time", startDate.atStartOfDay());
        }
        
        if (endDate != null) {
            daysWrapper.le("create_time", endDate.plusDays(1).atStartOfDay());
        }
        
        Map<String, Object> daysStats = overdueMapper.selectMaps(daysWrapper).get(0);
        
        // 组合统计结果
        result.put("statusStats", statusStats);
        result.put("daysStats", daysStats);
        result.put("startDate", startDate);
        result.put("endDate", endDate);
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int checkAndGenerateOverdueRecords() {
        int count = 0;
        
        // 1. 查询过期且未还款的还款计�?
        LambdaQueryWrapper<LoanRepaymentPlan> planWrapper = new LambdaQueryWrapper<>();
        planWrapper.lt(LoanRepaymentPlan::getRepayDate, LocalDate.now());
        planWrapper.eq(LoanRepaymentPlan::getRepayStatus, 10); // 未还款状�?
        planWrapper.eq(LoanRepaymentPlan::getIsDeleted, 0);
        
        List<LoanRepaymentPlan> plans = repaymentPlanMapper.selectList(planWrapper);
        
        for (LoanRepaymentPlan plan : plans) {
            // 2. 检查是否已经有逾期记录
            LambdaQueryWrapper<LoanOverdue> overdueWrapper = new LambdaQueryWrapper<>();
            overdueWrapper.eq(LoanOverdue::getPlanId, plan.getPlanId());
            overdueWrapper.eq(LoanOverdue::getIsDeleted, 0);
            
            int exists = overdueMapper.selectCount(overdueWrapper).intValue();
            if (exists > 0) {
                continue; // 已存在逾期记录，跳�?
            }
            
            // 3. 获取合同信息
            LoanContract contract = contractMapper.selectById(plan.getContractId());
            if (contract == null) {
                log.error("合同不存在，合同ID: {}", plan.getContractId());
                continue;
            }
            
            // 4. 计算逾期天数
            int overdueDays = (int) ChronoUnit.DAYS.between(plan.getRepayDate(), LocalDate.now());
            
            // 5. 计算罚息 (假设罚息利率�?.1%/�?
            BigDecimal penaltyRate = new BigDecimal("0.001");
            BigDecimal penalty = plan.getRepayAmount().multiply(penaltyRate)
                    .multiply(new BigDecimal(overdueDays))
                    .setScale(2, RoundingMode.HALF_UP);
            
            // 6. 创建逾期记录
            LoanOverdue overdue = new LoanOverdue();
            overdue.setContractId(plan.getContractId());
            overdue.setContractNo(contract.getContractNo());
            overdue.setPlanId(plan.getPlanId());
            overdue.setCustId(contract.getCustId());
            overdue.setPeriod(plan.getTermNo());
            overdue.setDueDate(plan.getRepayDate());
            overdue.setDueAmount(plan.getRepayAmount());
            overdue.setPrincipal(plan.getPrincipal());
            overdue.setInterest(plan.getInterest());
            overdue.setOverdueDays(overdueDays);
            overdue.setPenalty(penalty);
            overdue.setPenaltyRate(penaltyRate);
            overdue.setTotalAmount(plan.getRepayAmount().add(penalty));
            overdue.setStatus("pending");
            overdue.setRemindCount(0);
            overdue.setCalcDate(LocalDate.now());
            overdue.setCreateTime(LocalDateTime.now());
            overdue.setIsDeleted(0);
            
            overdueMapper.insert(overdue);
            count++;
            
            // 7. 更新还款计划状态为逾期
            plan.setRepayStatus(30); // 逾期状�?
            plan.setUpdateTime(LocalDateTime.now());
            repaymentPlanMapper.updateById(plan);
        }
        
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updatePenaltyAmount() {
        int count = 0;
        
        // 1. 查询未结清的逾期记录
        LambdaQueryWrapper<LoanOverdue> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(LoanOverdue::getStatus, "settled");
        wrapper.eq(LoanOverdue::getIsDeleted, 0);
        
        List<LoanOverdue> overduList = overdueMapper.selectList(wrapper);
        
        for (LoanOverdue overdue : overduList) {
            // 2. 更新逾期天数
            LocalDate dueDate = overdue.getDueDate();
            int overdueDays = (int) ChronoUnit.DAYS.between(dueDate, LocalDate.now());
            
            // 3. 如果逾期天数有变化，更新罚息
            if (overdueDays > overdue.getOverdueDays()) {
                BigDecimal penaltyRate = overdue.getPenaltyRate();
                BigDecimal penalty = overdue.getDueAmount().multiply(penaltyRate)
                        .multiply(new BigDecimal(overdueDays))
                        .setScale(2, RoundingMode.HALF_UP);
                
                // 4. 更新逾期记录
                overdue.setOverdueDays(overdueDays);
                overdue.setPenalty(penalty);
                overdue.setTotalAmount(overdue.getDueAmount().add(penalty));
                overdue.setCalcDate(LocalDate.now());
                overdue.setUpdateTime(LocalDateTime.now());
                
                overdueMapper.updateById(overdue);
                count++;
            }
        }
        
        return count;
    }
} 
